home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Help Dialog / help.c < prev    next >
Encoding:
Text File  |  1996-06-04  |  24.8 KB  |  792 lines  |  [TEXT/CWIE]

  1. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊
  2. // help.c
  3. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊
  4.  
  5. // …………………………………………………………………………………………………………………………………………………………………………………………………………… includes
  6.  
  7. #include <Dialogs.h>
  8. #include <ToolUtils.h>
  9. #include <Resources.h>
  10.  
  11. // ……………………………………………………………………………………………………………………………………………………………………………………………………………… defines
  12.  
  13. #define rHelpModal                128
  14. #define  iOK                            1
  15. #define  iTextUserItem        2
  16. #define  iScrollBar                3
  17. #define  iPopupMenu                4
  18. #define  iButtonUserItem    5
  19. #define    rAlert                        129
  20. #define kTextInset                4
  21. #define kReturn                        0x0D
  22. #define kEnter                        0x03
  23.  
  24. // This block of defines will need to be changed to accommodate the ID of the 'TEXT'/
  25. // 'styl' resource associated with each of your popup menu items, and the starting 'PICT'
  26. // ID for the 'PICT's (if any) associated with each 'TEXT' resource.
  27.  
  28. #define    rTextIntroduction                128
  29. #define rTextCreatingText                129
  30. #define rTextModifyHelp                    130
  31. #define rTextAboutCricket                131                    
  32. #define    rPictIntroductionBase        128
  33. #define    rPictCreatingTextBase        129
  34. #define rPictAboutCricketBase        131                    
  35.  
  36. // …………………………………………………………………………………………………………………………………………………………………………………………………………… typedefs
  37.  
  38. typedef struct
  39. {
  40.     Rect                    bounds;
  41.     PicHandle            pictureHdl;
  42. } pictInfoRec;
  43.  
  44. typedef struct
  45. {
  46.     TEHandle            editRecHdl;
  47.     ControlHandle    scrollbarHdl;
  48.     SInt16                pictCount;
  49.     pictInfoRec        *pictInfoRecPtr;
  50. }    docRecord, ** docRecordHandle;
  51.  
  52. // ……………………………………………………………………………………………………………………………………………………………………………………… global variables
  53.  
  54. SInt16            gTextResourceID;
  55. SInt16            gPictResourceBaseID;
  56. RgnHandle        gSavedClipRgn = nil;
  57.  
  58. // ……………………………………………………………………………………………………………………………………………………………………………… function prototypes
  59.  
  60. void                        doHelp                            (void);
  61. void                        closeHelp                        (DialogPtr,GrafPtr);
  62. pascal void          drawHelp                        (DialogPtr,SInt16);
  63. Boolean                    getText                            (DialogPtr,SInt16,Rect);
  64. Boolean                    getPictureInfo            (DialogPtr,SInt16);
  65. void                        handleScrollBar            (DialogPtr,SInt16,Point);
  66. pascal void            actionProcedure            (ControlHandle,SInt16);
  67. void                        scrollTextAndPicts    (DialogPtr);
  68. void                         drawPictures                (DialogPtr,Rect *);
  69. pascal Boolean    helpDialogFilter        (DialogPtr,EventRecord *,SInt16 *);
  70. pascal void          drawButtonOutline        (DialogPtr,SInt16);
  71.  
  72. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ doHelp
  73.  
  74. // Open dialog and create a document record for the dialog, install draw functions, store
  75. // scroll bar handle in document record, create a style-aware edit record, get the text
  76. // and picture info relating to popup menu item No 1, do the ModalDialog loop (in which
  77. // popup menu selections are detected and handled), and close down on an OK button hit.
  78.  
  79. void  doHelp(void)
  80. {
  81.     DialogPtr                modalDlgPtr;
  82.     docRecordHandle    docRecHdl;
  83.     GrafPtr                    oldPort;
  84.     SInt16                    itemType,itemHit, menuItem;
  85.     Handle                    itemHdl;
  86.     Rect                        userItemRect, destRect, viewRect, itemRect;
  87.     ModalFilterUPP    helpDialogFilterUPP;                                                                                 // PowerPC
  88.     UserItemUPP            drawHelpUPP;                                                                                                 // PowerPC    
  89.     UserItemUPP            drawButtonOutlineUPP;                                                                                 // PowerPC
  90.  
  91.     helpDialogFilterUPP = NewModalFilterProc((ProcPtr) helpDialogFilter);                 // PowerPC
  92.     drawHelpUPP = NewUserItemProc((ProcPtr) drawHelp);                                                     // PowerPC
  93.     drawButtonOutlineUPP = NewUserItemProc((ProcPtr) drawButtonOutline);                 // PowerPC        
  94.  
  95.     if(!(modalDlgPtr = GetNewDialog(rHelpModal,nil,(WindowPtr) -1)))
  96.     {
  97.         ParamText("\pCannot open help dialog",nil,nil,nil);
  98.         StopAlert(rAlert,nil);
  99.         DisposeRoutineDescriptor(helpDialogFilterUPP);                                                         // PowerPC
  100.         DisposeRoutineDescriptor(drawHelpUPP);                                                                         // PowerPC
  101.         DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                         // PowerPC
  102.         return;
  103.     }
  104.  
  105.     if(!(docRecHdl = (docRecordHandle) NewHandle(sizeof(docRecord))))
  106.     {
  107.         ParamText("\pCannot get memory for required for help document record",nil,nil,nil);
  108.         StopAlert(rAlert,nil);
  109.         DisposDialog(modalDlgPtr);
  110.         DisposeRoutineDescriptor(helpDialogFilterUPP);                                                         // PowerPC
  111.         DisposeRoutineDescriptor(drawHelpUPP);                                                                         // PowerPC
  112.         DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                         // PowerPC
  113.         return;
  114.     }
  115.     
  116.     SetWRefCon(modalDlgPtr,(SInt32) docRecHdl);
  117.  
  118.     GetPort(&oldPort);
  119.     SetPort(modalDlgPtr);
  120.  
  121.     GetDialogItem(modalDlgPtr,iButtonUserItem,&itemType,&itemHdl,&userItemRect);
  122.     SetDialogItem(modalDlgPtr,iButtonUserItem,itemType,(Handle) drawButtonOutlineUPP,
  123.                                 &userItemRect);
  124.  
  125.     GetDialogItem(modalDlgPtr,iTextUserItem,&itemType,&itemHdl,&userItemRect);
  126.     SetDialogItem(modalDlgPtr,iTextUserItem,itemType,(Handle) drawHelpUPP,&userItemRect);
  127.  
  128.     GetDialogItem(modalDlgPtr,iScrollBar,&itemType,&itemHdl,&itemRect);
  129.     (*docRecHdl)->scrollbarHdl = (ControlHandle) itemHdl;
  130.  
  131.     InsetRect(&userItemRect,kTextInset,kTextInset / 2);
  132.     destRect = viewRect = userItemRect;
  133.     (*docRecHdl)->editRecHdl = TEStylNew(&destRect,&viewRect);
  134.  
  135.     (*docRecHdl)->pictInfoRecPtr = nil;
  136.     
  137.     // The value assigned to the first two global variables will need to be changed to the
  138.     // constants representing the ID of the 'TEXT" resource associated with the first popup
  139.     // menu item and the base ID of the pictures (if any) associated with that 'TEXT'
  140.     // resource.
  141.  
  142.     gTextResourceID            = rTextIntroduction;
  143.     gPictResourceBaseID    = rPictIntroductionBase;
  144.  
  145.     if(!(getText(modalDlgPtr,gTextResourceID,viewRect)))
  146.     {
  147.         DisposeRoutineDescriptor(helpDialogFilterUPP);                                                         // PowerPC
  148.         DisposeRoutineDescriptor(drawHelpUPP);                                                                         // PowerPC
  149.         DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                         // PowerPC
  150.         closeHelp(modalDlgPtr,oldPort);
  151.         return;
  152.     }
  153.     if(!(getPictureInfo(modalDlgPtr,gPictResourceBaseID)))
  154.     {
  155.         DisposeRoutineDescriptor(helpDialogFilterUPP);                                                         // PowerPC
  156.         DisposeRoutineDescriptor(drawHelpUPP);                                                                         // PowerPC
  157.         DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                         // PowerPC
  158.         closeHelp(modalDlgPtr,oldPort);
  159.         return;
  160.     }
  161.         
  162.     gSavedClipRgn = NewRgn();
  163.  
  164.     ShowWindow(modalDlgPtr);
  165.  
  166.     do 
  167.     {
  168.         ModalDialog((ModalFilterUPP) helpDialogFilterUPP,&itemHit);
  169.     
  170.         if(itemHit == iPopupMenu)
  171.         {
  172.             SetControlValue((*docRecHdl)->scrollbarHdl,0);
  173.  
  174.             GetDialogItem(modalDlgPtr,iPopupMenu,&itemType,&itemHdl,&itemRect);
  175.             menuItem = GetControlValue((ControlHandle) itemHdl);
  176.  
  177.             // This switch is the final modification you require.  You need one case for each
  178.             // item in your popup menu.  At each case, you need to assign the ID of the
  179.             // relevant 'TEXT'/'styl' resource to gTextResourceID and, where appropriate, the
  180.             // base 'PICT' resource ID for the 'PICT' resources associated with that
  181.             // particular 'TEXT' resource.
  182.             
  183.             switch(menuItem)
  184.             {
  185.                 case 1:
  186.                     gTextResourceID         = rTextIntroduction;
  187.                     gPictResourceBaseID = rPictIntroductionBase;
  188.                     break;
  189.                 
  190.                 case 2:
  191.                     gTextResourceID         = rTextCreatingText;
  192.                     gPictResourceBaseID = rPictCreatingTextBase;
  193.                     break;
  194.  
  195.                 case 3:
  196.                     gTextResourceID         = rTextModifyHelp;
  197.                     break;
  198.  
  199.                 case 5:
  200.                     gTextResourceID            = rTextAboutCricket;
  201.                     gPictResourceBaseID    = rPictAboutCricketBase;
  202.                 break;
  203.             }
  204.             
  205.             if(!(getText(modalDlgPtr,gTextResourceID,viewRect)))
  206.             {
  207.                 DisposeRoutineDescriptor(helpDialogFilterUPP);                                                 // PowerPC
  208.                 DisposeRoutineDescriptor(drawHelpUPP);                                                                 // PowerPC
  209.                 DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                 // PowerPC
  210.                 closeHelp(modalDlgPtr,oldPort);
  211.                 return;
  212.             }
  213.             if(!(getPictureInfo(modalDlgPtr,gPictResourceBaseID)))
  214.             {
  215.                 DisposeRoutineDescriptor(helpDialogFilterUPP);                                                 // PowerPC
  216.                 DisposeRoutineDescriptor(drawHelpUPP);                                                                 // PowerPC
  217.                 DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                 // PowerPC
  218.                 closeHelp(modalDlgPtr,oldPort);
  219.                 return;
  220.             }
  221.  
  222.             drawPictures(modalDlgPtr,&viewRect);
  223.         }
  224.             
  225.     } while(itemHit != iOK);
  226.         
  227.     DisposeRoutineDescriptor(helpDialogFilterUPP);                                                             // PowerPC
  228.     DisposeRoutineDescriptor(drawHelpUPP);                                                                             // PowerPC
  229.     DisposeRoutineDescriptor(drawButtonOutlineUPP);                                                             // PowerPC
  230.     closeHelp(modalDlgPtr,oldPort);
  231.  
  232.     return;
  233. }
  234.  
  235. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ closeHelp
  236.  
  237. // If they exist, dispose of saved clip region, the text edit record, the array of
  238. // pictInfoRec records, and the picture records.  Then dispose of the dialog's document
  239. // record and, finally, the dialog record.
  240.  
  241. void  closeHelp(DialogPtr modalDlgPtr,GrafPtr oldPort)
  242. {
  243.     docRecordHandle    docRecHdl;
  244.     TEHandle                editRecHdl;
  245.     SInt16                    a;
  246.     
  247.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  248.     editRecHdl = (*docRecHdl)->editRecHdl;
  249.  
  250.     if(gSavedClipRgn)
  251.         DisposeRgn(gSavedClipRgn);
  252.  
  253.     if((*docRecHdl)->editRecHdl)
  254.         TEDispose((*docRecHdl)->editRecHdl);
  255.  
  256.     if((*docRecHdl)->pictInfoRecPtr)
  257.     {
  258.         for(a=0;a<(*docRecHdl)->pictCount;a++)
  259.             ReleaseResource((Handle) (*docRecHdl)->pictInfoRecPtr[a].pictureHdl);
  260.         DisposPtr((Ptr) (*docRecHdl)->pictInfoRecPtr);
  261.     }
  262.  
  263.     DisposeHandle((Handle) docRecHdl);
  264.     DisposDialog(modalDlgPtr);
  265.  
  266.     SetPort(oldPort);
  267. }
  268.  
  269. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ drawHelp
  270.  
  271. // Installed in a user item.  Called whenever dialog gets update event. Draws some
  272. // shadow boxes, the rectangle in which text and picts will be displayed, and the popup
  273. // menu title.  More importantly, calls TEUpdate to redraw the text, and drawPictures to
  274. // draw the pictures.
  275.  
  276. pascal void  drawHelp(DialogPtr modalDlgPtr,SInt16 theItem)
  277. {
  278.     PenState                oldPenState;
  279.     Handle                    itemHdl;
  280.     Rect                        itemRect, viewRect, theRect;
  281.     SInt16                    itemType;
  282.     docRecordHandle    docRecHdl;
  283.     TEHandle                editRecHdl;
  284.     RGBColor                whiteColour = { 0xFFFF, 0xFFFF, 0xFFFF };
  285.     RGBColor                greyColour    = { 0x4444, 0x4444, 0x4444 };
  286.     RGBColor                blackColour    = { 0x0000, 0x0000, 0x0000 };
  287.  
  288.     GetPenState(&oldPenState);
  289.  
  290.     GetDialogItem(modalDlgPtr,iTextUserItem,&itemType,&itemHdl,&itemRect);
  291.     InsetRect(&itemRect,1,1);
  292.  
  293.     RGBBackColor(&whiteColour);
  294.     FillRect(&itemRect,&qd.white);
  295.  
  296.     InsetRect(&itemRect,-1,-1);
  297.     FrameRect(&itemRect);
  298.  
  299.     // Draw shadow boxes around the dialog and around the internal text box.
  300.  
  301.     PenSize(2,2);
  302.     RGBForeColor(&whiteColour);
  303.     SetRect(&theRect,0,0,449,385);
  304.     FrameRect(&theRect);
  305.     RGBForeColor(&greyColour);
  306.     MoveTo(theRect.right - 2,theRect.top + 2);
  307.     LineTo(theRect.right - 2,theRect.bottom - 2);
  308.     MoveTo(theRect.left + 2,theRect.bottom - 2);
  309.     LineTo(theRect.right - 2,theRect.bottom - 2);
  310.     
  311.     InsetRect(&itemRect,-3,-3);
  312.     itemRect.right += 16;
  313.     RGBForeColor(&greyColour);
  314.     FrameRect(&itemRect);
  315.     RGBForeColor(&whiteColour);
  316.     MoveTo(itemRect.right - 2,itemRect.top + 2);
  317.     LineTo(itemRect.right - 2,itemRect.bottom - 2);
  318.     MoveTo(itemRect.left + 2,itemRect.bottom - 2);
  319.     LineTo(itemRect.right - 2,itemRect.bottom - 2);
  320.     
  321.     // Draw the popup menu title. (The title has been omitted from the control resource.
  322.     // Drawing the title here means that the background will be drawn in grey rather 
  323.     // than white. 
  324.  
  325.     TextFont(0);
  326.     MoveTo(110,32);
  327.     RGBForeColor(&blackColour);
  328.     DrawString("\pHelp Topic:");
  329.  
  330.     // The important stuff - draw the text and the pictures.
  331.     
  332.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  333.     editRecHdl = (*docRecHdl)->editRecHdl;
  334.     viewRect = (*editRecHdl)->viewRect;
  335.  
  336.     TEUpdate(&viewRect,editRecHdl);
  337.     drawPictures(modalDlgPtr,&viewRect);
  338.  
  339.     SetPenState(&oldPenState);
  340. }
  341.  
  342. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ getText
  343.  
  344. // Delete any existing text in the text edit record and set the scroll bar control value
  345. // to 0.  Get 'TEXT' and 'styl' resources relating to the pop menu item chosen, insert
  346. // the text in the edit text record, release the 'TEXT' and 'styl' resources, highlight
  347. // the scroll bar and set the scroll bar control maximum value if the text height is 
  348. // greater than the height of the view rectangle, otherwise just un-highlight the scroll
  349. // bar.
  350.  
  351. Boolean  getText(DialogPtr modalDlgPtr,SInt16 textResourceID,Rect viewRect)
  352. {
  353.     docRecordHandle    docRecHdl;
  354.     TEHandle                editRecHdl;
  355.     Handle                    helpTextHdl;
  356.     StScrpHandle        stylScrpRecHdl;
  357.     SInt16                    numberOfLines, heightOfText, heightToScroll;
  358.  
  359.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  360.     editRecHdl = (*docRecHdl)->editRecHdl;
  361.  
  362.     TESetSelect(0,32767,editRecHdl);
  363.     TEDelete(editRecHdl);
  364.     
  365.     (*editRecHdl)->destRect = (*editRecHdl)->viewRect;
  366.     SetControlValue((*docRecHdl)->scrollbarHdl,0);
  367.             
  368.     helpTextHdl = GetResource('TEXT',textResourceID);
  369.     if(helpTextHdl == nil)
  370.     {
  371.         ParamText("\pCannot get 'TEXT' resource for help dialog",nil,nil,nil);
  372.         StopAlert(rAlert,nil);
  373.         return false;
  374.     }
  375.  
  376.     stylScrpRecHdl = (StScrpHandle) GetResource('styl',textResourceID);
  377.     if(stylScrpRecHdl == nil)
  378.     {
  379.         ParamText("\pCannot get 'styl' resource for help dialog",nil,nil,nil);
  380.         StopAlert(rAlert,nil);
  381.         return false;
  382.     }
  383.         
  384.     TEStylInsert(*helpTextHdl,GetHandleSize(helpTextHdl),stylScrpRecHdl,editRecHdl);
  385.  
  386.     ReleaseResource(helpTextHdl);
  387.     ReleaseResource((Handle) stylScrpRecHdl);
  388.  
  389.     numberOfLines = (*editRecHdl)->nLines;
  390.     heightOfText = TEGetHeight((SInt32) numberOfLines,1,editRecHdl);
  391.  
  392.     if(heightOfText >  (viewRect.bottom - viewRect.top))
  393.     {
  394.         heightToScroll = TEGetHeight((SInt32) numberOfLines,1,editRecHdl) -
  395.                                                                  (viewRect.bottom - viewRect.top);
  396.         SetControlMaximum((*docRecHdl)->scrollbarHdl,heightToScroll);
  397.         HiliteControl((*docRecHdl)->scrollbarHdl,0);
  398.     }
  399.     else
  400.     {
  401.         HiliteControl((*docRecHdl)->scrollbarHdl,255);
  402.     }
  403.  
  404.     return true;
  405. }
  406.  
  407. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ getPictureInfo
  408.  
  409. // If any currently exist, dispose of existing picture records and pictInfoRect records.
  410. // Count the number of option_space characters in the text.  If none exist, return.
  411. // Otherwise, create an array of pictInfoRec records, store the handle in the dialog's
  412. // document record, then stores the PICT handles and picFrames (converted to unscrolled
  413. // screen coordinates) in the pictInfoRec records.
  414.  
  415. Boolean  getPictureInfo(DialogPtr modalDlgPtr,SInt16 firstPictID)
  416. {
  417.     docRecordHandle    docRecHdl;
  418.     TEHandle                editRecHdl;
  419.     Handle                    textHdl;
  420.     SInt32                    offset, textSize;
  421.     SInt16                    numberOfPicts, a, lineHeight, fontAscent;
  422.     SInt8                        optionSpace[1] = "\xCA";
  423.     pictInfoRec            *pictInfoPtr;
  424.     Point                        picturePoint;
  425.     TextStyle                whatStyle;
  426.     
  427.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  428.  
  429.     if((*docRecHdl)->pictInfoRecPtr != nil)
  430.     {
  431.         for(a=0;a<(*docRecHdl)->pictCount;a++)
  432.             ReleaseResource((Handle) (*docRecHdl)->pictInfoRecPtr[a].pictureHdl);
  433.  
  434.         DisposePtr((Ptr) (*docRecHdl)->pictInfoRecPtr);
  435.         (*docRecHdl)->pictInfoRecPtr = nil;
  436.     }
  437.  
  438.     (*docRecHdl)->pictCount = 0;
  439.  
  440.     editRecHdl = (*docRecHdl)->editRecHdl;
  441.     textHdl = (*editRecHdl)->hText;
  442.  
  443.     textSize = GetHandleSize(textHdl);
  444.     offset = 0;
  445.     numberOfPicts = 0;
  446.  
  447.     HLock(textHdl);
  448.  
  449.     offset = Munger(textHdl,offset,optionSpace,1,nil,nil);
  450.     while((offset >= 0) && (offset <= textSize))
  451.     {
  452.         numberOfPicts++;
  453.         offset++;
  454.         offset = Munger(textHdl,offset,optionSpace,1,nil,nil);        
  455.     }
  456.     
  457.     if(numberOfPicts == 0)
  458.     {
  459.         HUnlock(textHdl);
  460.         return true;
  461.     }
  462.         
  463.     pictInfoPtr = (pictInfoRec *) NewPtr(sizeof(pictInfoRec) * numberOfPicts);
  464.     (*docRecHdl)->pictInfoRecPtr = pictInfoPtr;
  465.  
  466.     offset = 0L;
  467.  
  468.     for(a=0;a<numberOfPicts;a++)
  469.     {
  470.         pictInfoPtr[a].pictureHdl = (PicHandle) GetResource('PICT',firstPictID + a);
  471.         if(pictInfoPtr[a].pictureHdl == nil)
  472.         {
  473.             ParamText("\pCannot get 'PICT' resource for help dialog",nil,nil,nil);
  474.             StopAlert(rAlert,nil);
  475.             return false;
  476.         }
  477.  
  478.         offset = Munger(textHdl,offset,optionSpace,1,nil,nil);
  479.         picturePoint = TEGetPoint((SInt16)offset,editRecHdl);
  480.  
  481.         TEGetStyle(offset,&whatStyle,&lineHeight, &fontAscent,editRecHdl);
  482.         picturePoint.v -= lineHeight;
  483.         offset++;
  484.         pictInfoPtr[a].bounds = (**pictInfoPtr[a].pictureHdl).picFrame;
  485.  
  486.         OffsetRect(&pictInfoPtr[a].bounds,
  487.                              (((*editRecHdl)->destRect.right + (*editRecHdl)->destRect.left) -
  488.                              (pictInfoPtr[a].bounds.right + pictInfoPtr[a].bounds.left) ) / 2,
  489.                              - pictInfoPtr[a].bounds.top + picturePoint.v);
  490.     }
  491.     
  492.     (*docRecHdl)->pictCount = a;
  493.     
  494.     HUnlock(textHdl);
  495.  
  496.     return true;
  497. }
  498.  
  499. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ handleScrollBar
  500.  
  501. // Called by helpDialogFilter to handle mouse-down events in the scroll bar.
  502.  
  503. void  handleScrollBar(DialogPtr modalDlgPtr,SInt16 thePart,Point mouseXY)
  504. {
  505.     docRecordHandle        docRecHdl;
  506.     ControlActionUPP    actionProcedureUPP;                                                                                 // PowerPC
  507.  
  508.     actionProcedureUPP = NewControlActionProc((ProcPtr) actionProcedure);                 // PowerPC
  509.  
  510.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  511.  
  512.     if(thePart == inThumb)
  513.     {
  514.         if(TrackControl((*docRecHdl)->scrollbarHdl,mouseXY,nil))
  515.             scrollTextAndPicts(modalDlgPtr);
  516.     }
  517.     else
  518.         TrackControl((*docRecHdl)->scrollbarHdl,mouseXY,(ControlActionUPP) actionProcedureUPP);    
  519.  
  520.     DisposeRoutineDescriptor(actionProcedureUPP);                                                                 // PowerPC
  521. }
  522.  
  523. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ actionProcedure
  524.  
  525. // Called repeatedly by handleScrollBar while the mouse button remains down in the scroll
  526. // arrows or the gray areas.  Determines the distance to scroll, sets the new scoll bar
  527. // control value accordingly, and calls scrollTextandPicts to effect the scrolling.
  528.  
  529. pascal void  actionProcedure(ControlHandle scrollbarHdl,SInt16 partCode)
  530. {
  531.     docRecordHandle    docRecHdl;
  532.     DialogPtr                modalDlgPtr;
  533.     TEHandle                editRecHdl;
  534.     SInt16                    delta, oldValue, offset, lineHeight, fontAscent;
  535.     Point                        thePoint;
  536.     Rect                        viewRect;
  537.     TextStyle                style;
  538.  
  539.     if(partCode)
  540.     {
  541.         modalDlgPtr = (*scrollbarHdl)->contrlOwner;
  542.         docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  543.         editRecHdl = (*docRecHdl)->editRecHdl;
  544.         viewRect = (*editRecHdl)->viewRect;
  545.         thePoint.h = viewRect.left + kTextInset;
  546.         
  547.         switch(partCode)
  548.         {
  549.             case inUpButton:
  550.                 // Set delta so that, after the scroll, the top of the incoming line
  551.                 // of text will be positioned cleanly at top of the view rectangle 
  552.                 thePoint.v = viewRect.top - 4;
  553.                 offset = TEGetOffset(thePoint,editRecHdl);
  554.                 thePoint = TEGetPoint(offset,editRecHdl);
  555.                 TEGetStyle(offset,&style,&lineHeight,&fontAscent,editRecHdl);
  556.                 delta = thePoint.v - lineHeight - viewRect.top;
  557.                 break;
  558.  
  559.             case inDownButton:
  560.                 // Set delta so that, after the scroll, the bottom of the incoming line
  561.                 // of text will be positioned cleanly at bottom of the view rectangle 
  562.                 thePoint.v = viewRect.bottom + 2;
  563.                 offset = TEGetOffset(thePoint,editRecHdl);
  564.                 thePoint = TEGetPoint(offset,editRecHdl);
  565.                 delta = thePoint.v - viewRect.bottom;
  566.                 break;
  567.  
  568.             case inPageUp:
  569.                 // Set delta so that, after the scroll, the top of the top line
  570.                 // of text will be positioned cleanly at the top of the view rectangle
  571.                 // and the line of text which was previously at the top will still be
  572.                 // visible at the bottom of the view rectangle 
  573.                 thePoint.v = viewRect.top + 2;
  574.                 offset = TEGetOffset(thePoint,editRecHdl);
  575.                 thePoint = TEGetPoint(offset,editRecHdl);
  576.                 TEGetStyle(offset,&style,&lineHeight,&fontAscent,editRecHdl);
  577.                 thePoint.v += lineHeight - fontAscent;
  578.                 thePoint.v -= viewRect.bottom - viewRect.top;
  579.                 offset = TEGetOffset(thePoint,editRecHdl);
  580.                 thePoint = TEGetPoint(offset,editRecHdl);
  581.                 TEGetStyle(offset,&style,&lineHeight,&fontAscent,editRecHdl);
  582.                 delta = thePoint.v - viewRect.top;
  583.                 if(offset == 0)
  584.                     delta -= lineHeight;
  585.                 break;
  586.                 
  587.             case inPageDown:
  588.                 // Set delta so that, after the scroll, the bottom of the bottom line
  589.                 // of text will be positioned cleanly at the bottom of the view rectangle
  590.                 // and the line of text which was previously at the bottom will still be
  591.                 // visible at the top of the view rectangle 
  592.                 thePoint.v = viewRect.bottom - 2;
  593.                 offset = TEGetOffset(thePoint,editRecHdl);
  594.                 thePoint = TEGetPoint(offset,editRecHdl);
  595.                 TEGetStyle(offset,&style,&lineHeight,&fontAscent,editRecHdl);
  596.                 thePoint.v -= fontAscent;
  597.                 thePoint.v += viewRect.bottom - viewRect.top;
  598.                 offset = TEGetOffset(thePoint,editRecHdl);
  599.                 thePoint = TEGetPoint(offset,editRecHdl);
  600.                 TEGetStyle(offset,&style,&lineHeight,&fontAscent,editRecHdl);
  601.                 delta =  thePoint.v - lineHeight - viewRect.bottom;
  602.                 if(offset == (**editRecHdl).teLength)
  603.                     delta += lineHeight;
  604.                 break;
  605.         }
  606.  
  607.         oldValue = GetCtlValue(scrollbarHdl);
  608.  
  609.         if(((delta < 0) && (oldValue > 0)) || ((delta > 0) && 
  610.              (oldValue < GetControlMaximum(scrollbarHdl))))
  611.         {
  612.             // When this routine is called, TextEdit may have set the clipping region to the
  613.             // viewRect rectangle, so we reset it here to make sure the scroll bar gets drawn.
  614.  
  615.              GetClip(gSavedClipRgn);
  616.             ClipRect(&modalDlgPtr->portRect);
  617.  
  618.             SetControlValue(scrollbarHdl,oldValue + delta);
  619.             SetClip(gSavedClipRgn);
  620.         }
  621.  
  622.         scrollTextAndPicts(modalDlgPtr);
  623.     }
  624. }
  625.  
  626. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ scrollTextAndPicts
  627.  
  628. // Called by handleScrollBar and actionProcedure to scroll the text and pictures into 
  629. // sync with the scroll bar's control value.
  630.  
  631. void  scrollTextAndPicts(DialogPtr modalDlgPtr)
  632. {
  633.     docRecordHandle    docRecHdl;
  634.     TEHandle                editRecHdl;
  635.     SInt16                    scrollDown, oldScroll;
  636.     Rect                        updateRect;
  637.  
  638.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  639.     editRecHdl = (*docRecHdl)->editRecHdl;
  640.  
  641.     oldScroll = (*editRecHdl)->viewRect.top -(**editRecHdl).destRect.top;
  642.     scrollDown = oldScroll - GetCtlValue((*docRecHdl)->scrollbarHdl);
  643.     if(scrollDown == 0)
  644.         return;
  645.  
  646.     TEScroll(0,scrollDown,editRecHdl);
  647.  
  648.     if((*docRecHdl)->pictCount == 0)
  649.         return;
  650.         
  651.     updateRect = (*editRecHdl)->viewRect;
  652.  
  653.     if(scrollDown > 0)
  654.     {
  655.         if(scrollDown < (updateRect.bottom - updateRect.top))
  656.             updateRect.bottom = updateRect.top + scrollDown;
  657.     }
  658.     else
  659.     {
  660.         if( - scrollDown < (updateRect.bottom - updateRect.top))
  661.             updateRect.top = updateRect.bottom + scrollDown;
  662.     }
  663.  
  664.     drawPictures(modalDlgPtr,&updateRect);
  665. }
  666.  
  667. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ drawPictures
  668.  
  669. // Called by drawHelp and scrollTextAndPicts to draw the pictures.  For all pictures,
  670. // checks whether the picture's rectangle is within the update rectangle.  If is is,
  671. // the clipping rectangle is set to the update rectangle and the picture is drawn.
  672.  
  673. void  drawPictures(DialogPtr modalDlgPtr,Rect *updateRect)
  674. {
  675.     docRecordHandle    docRecHdl;
  676.     TEHandle                editRecHdl;
  677.     SInt16                    pictCount, pictIndex, vOffset;
  678.     PicHandle                thePictHdl;
  679.     Rect                        pictLocRect, dummyRect;
  680.     
  681.     docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  682.     editRecHdl = (*docRecHdl)->editRecHdl;
  683.  
  684.     vOffset = (*editRecHdl)->destRect.top - (*editRecHdl)->viewRect.top - kTextInset;
  685.     pictCount = (*docRecHdl)->pictCount;
  686.  
  687.     for(pictIndex = 0;pictIndex < pictCount;pictIndex++)
  688.     {
  689.         pictLocRect = (*docRecHdl)->pictInfoRecPtr[pictIndex].bounds;
  690.     OffsetRect(&pictLocRect,0,vOffset);
  691.  
  692.         if(!SectRect(&pictLocRect,updateRect,&dummyRect))
  693.             continue;
  694.  
  695.         thePictHdl = (*docRecHdl)->pictInfoRecPtr[pictIndex].pictureHdl;
  696.  
  697.         LoadResource((Handle) thePictHdl);
  698.         HLock((Handle) thePictHdl);
  699.  
  700.         GetClip(gSavedClipRgn);
  701.         ClipRect(updateRect);
  702.         DrawPicture(thePictHdl,&pictLocRect);
  703.  
  704.         SetClip(gSavedClipRgn);
  705.         HUnlock((Handle) thePictHdl);
  706.     }
  707. }
  708.  
  709. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ helpDialogFilter
  710.  
  711. // Apart from the usual Return and Enter key handling, this filter handles the case of
  712. // a mouse-down in the scroll bar by calling handleScrollBar.
  713.  
  714. pascal  Boolean helpDialogFilter(DialogPtr modalDlgPtr, EventRecord    *eventRecPtr,
  715.                                                                  SInt16 *itemHit)
  716. {
  717.     docRecordHandle    docRecHdl;
  718.     SInt16                    handledEvent, itemType, thePart;
  719.     SInt8                        charCode;
  720.     Rect                        itemRect;
  721.     Handle                    itemHdl;
  722.     Point                        mouseXY;
  723.     SInt32                    finalTicks;
  724.     ControlHandle        controlHdl;
  725.  
  726.     handledEvent = false;
  727.  
  728.     switch(eventRecPtr->what)
  729.     {
  730.         case keyDown:
  731.         case autoKey:
  732.             charCode = eventRecPtr->message & charCodeMask;
  733.             if((charCode == (SInt8) kReturn) || (charCode == (SInt8) kEnter))
  734.             {
  735.                 GetDialogItem(modalDlgPtr,iOK,&itemType,&itemHdl,&itemRect);
  736.                 HiliteControl((ControlHandle) itemHdl,inButton);
  737.                 Delay(10,&finalTicks);
  738.                 HiliteControl((ControlHandle) itemHdl,0);
  739.                 handledEvent = true;
  740.                 *itemHit = iOK;
  741.             }
  742.             break;
  743.             
  744.         case mouseDown:
  745.             mouseXY = eventRecPtr->where;
  746.             GlobalToLocal(&mouseXY);
  747.             thePart = FindControl(mouseXY,modalDlgPtr,&controlHdl);
  748.             docRecHdl = (docRecordHandle) GetWRefCon(modalDlgPtr);
  749.             if(controlHdl == (*docRecHdl)->scrollbarHdl)
  750.             {
  751.                 handleScrollBar(modalDlgPtr,thePart,mouseXY);
  752.                 *itemHit = iScrollBar;
  753.                 handledEvent = true;
  754.             }    
  755.             break;
  756.     }
  757.  
  758.     return handledEvent;
  759. }
  760.  
  761. // ◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊ drawButtonOutline
  762.  
  763. pascal void  drawButtonOutline(DialogPtr dialogPtr,SInt16 theItem)
  764. {
  765.     WindowPtr    oldPort;
  766.     PenState    oldPenState;
  767.     SInt16        itemType;
  768.     Handle        itemHandle;
  769.     Rect            itemRect;
  770.     SInt8            buttonOval;
  771.  
  772.     GetPort(&oldPort);
  773.     GetPenState(&oldPenState);
  774.  
  775.     GetDialogItem(dialogPtr,iOK,&itemType,&itemHandle,&itemRect);
  776.     SetPort((*(ControlHandle) itemHandle)->contrlOwner);
  777.     InsetRect(&itemRect,-4,-4);
  778.  
  779.     buttonOval = (itemRect.bottom - itemRect.top) / 2 + 2;
  780.  
  781.     PenPat(&qd.black);
  782.     PenSize(3,3);
  783.     FrameRoundRect(&itemRect,buttonOval,buttonOval);
  784.  
  785.     SetPenState(&oldPenState);
  786.     SetPort(oldPort);
  787. }
  788.  
  789. //◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊
  790.  
  791.  
  792.